package org.alwayssuper;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.alwayssuper.protocol.basics.GBTMessage;
import org.alwayssuper.protocol.codec.GBTMessageDecoder;
import org.alwayssuper.protocol.codec.GBTMessageEncoder;

/**
 * GBT32960协议压力测试工具
 * 用于测试GBT32960协议编码解码的性能和稳定性
 * @author alwaysSuper
 * https://gitee.com/alwayssuper/gbt32960-server
 */
public class GBTDarkRepulsor {

    private static final GBTMessageDecoder decoder = new GBTMessageDecoder("org.alwayssuper.protocol");
    private static final GBTMessageEncoder encoder = new GBTMessageEncoder("org.alwayssuper.protocol");

    /**
     * 主程序 - 执行压力测试
     */
    public static void main(String[] args) {
        System.out.println("GBT32960协议压力测试工具");
        System.out.println("====================================================================================\n");
        
        // 使用2025版本G02实时数据进行压力测试
        String hex2025 = "242402FE4C46504832413142304B3141313233343501003919081F0E1E000101030102580005464E0E4A788430010E2CEC060100000003010105000100000000080101000C191B1D1F21235F64696E7378D1";
        
        // 使用2016版本G02实时数据进行压力测试  
        String hex2016 = "232302FE4C41395A414C343334483043484430303701013913010C00003901010401000000001F6C0CF8271062010075000000020101012B4E204E20270D1627100801010CF8271000640001640CFA0CFC0CFC0CFC0CFA0CFB0CFC0CFD0CFB0CFC0CFB0CFB0CFB0CFC0CFB0CFB0CFC0CFC0CFC0CFD0CFD0CFD0CFD0CFC0CFD0CFA0CFB0CFC0CFB0CFB0CFD0CFD0CFD0CFD0CFD0CFD0CFD0CFD0CFD0CFE0CFE0CFE0CFE0CFF0CFE0CFF0CFF0CFE0CFE0CFD0CFC0CFB0CFC0CFC0CFE0CFD0CFE0CFE0CFD0CFE0CFF0D000CFF0CFE0CFF0CFF0CFE0CFF0CFF0CFF0CFE0CFF0D000D000CFF0CFB0CFC0CFB0CFB0CFC0CFC0CFD0CFD0CFD0CFD0CFD0CFD0CFD0CFD0CFE0CFD0CFD0CFD0CFD0CFB0CFD0CFE0CFE0CFE0D0009010100142C2C2B2B2A2A2C2C2D2C2C2C2D2B2B2B2B2B2B2C06013E0D0001010CFA01092D01052A050006EBD27F026183CA0700000000000000000044";
        
        // G01登入报文压力测试
        String hexLogin = "232301FE4C41395A414C343334483043484430303701001E130801071F0C000138393836303631393030303031363134323538340100B6";
        
        System.out.println("开始压力测试...");
        
        // 测试不同类型的报文
        performanceTest("2025版G02报文", hex2025, 50000);
        performanceTest("2016版G02报文", hex2016, 50000);
        performanceTest("G01登入报文", hexLogin, 50000);
        
        // 无限循环压力测试(可选)
        // continuousStressTest(hex2025);
    }

    /**
     * 执行指定次数的性能测试
     * @param testName 测试名称
     * @param hex 十六进制报文
     * @param iterations 测试次数
     */
    public static void performanceTest(String testName, String hex, int iterations) {
        System.out.println("---------- " + testName + " 性能测试 ----------");
        System.out.println("测试次数: " + iterations);
        System.out.println("报文长度: " + (hex.length() / 2) + " 字节");
        
        ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hex));
        long startTime = System.currentTimeMillis();
        
        int successCount = 0;
        int errorCount = 0;
        
        try {
            for (int i = 0; i < iterations; i++) {
                try {
                    // 解码
                    GBTMessage message = decoder.decode(buf.duplicate());
                    
                    // 修改序列号模拟不同报文
                    if (message != null) {
                        message.setSerialNo((message.getSerialNo() + 1) % 65536);
                        
                        // 重新编码
                        ByteBuf encodedBuf = encoder.encode(message);
                        
                        // 释放编码后的缓冲区
                        if (encodedBuf != null) {
                            encodedBuf.release();
                        }
                        
                        successCount++;
                    }
                } catch (Exception e) {
                    errorCount++;
                    if (errorCount <= 10) { // 只打印前10个错误避免日志过多
                        System.err.println("第" + i + "次测试出错: " + e.getMessage());
                    }
                }
            }
        } finally {
            buf.release();
        }
        
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        
        System.out.println("测试完成!");
        System.out.println("总耗时: " + totalTime + "ms");
        System.out.println("成功次数: " + successCount);
        System.out.println("失败次数: " + errorCount);
        System.out.println("成功率: " + String.format("%.2f", (successCount * 100.0 / iterations)) + "%");
        System.out.println("平均处理时间: " + String.format("%.3f", (totalTime * 1.0 / iterations)) + "ms/次");
        System.out.println("处理速度: " + String.format("%.0f", (iterations * 1000.0 / totalTime)) + " 次/秒");
        System.out.println();
    }

    /**
     * 持续压力测试(无限循环)
     * @param hex 十六进制报文
     */
    public static void continuousStressTest(String hex) {
        System.out.println("开始持续压力测试 (Ctrl+C停止)...");
        ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hex));
        
        int batchSize = 100000; // 每批处理10万次
        int batchCount = 0;
        
        while (true) {
            long batchStart = System.currentTimeMillis();
            
            for (int i = 0; i < batchSize; i++) {
                try {
                    GBTMessage message = decoder.decode(buf.duplicate());
                    
                    if (message != null) {
                        message.setSerialNo((message.getSerialNo() + 1) % 65536);
                        
                        ByteBuf encodedBuf = encoder.encode(message);
                        if (encodedBuf != null) {
                            encodedBuf.release();
                        }
                    }
                } catch (Exception e) {
                    // 忽略错误，继续测试
                }
            }
            
            long batchTime = System.currentTimeMillis() - batchStart;
            batchCount++;
            
            System.out.println("批次 " + batchCount + ": " + batchTime + "ms, " + 
                             String.format("%.0f", (batchSize * 1000.0 / batchTime)) + " 次/秒, " +
                             "总处理: " + (batchCount * batchSize) + " 次");
        }
    }

    /**
     * 内存泄漏测试
     * @param hex 测试报文
     * @param iterations 测试次数
     */
    public static void memoryLeakTest(String hex, int iterations) {
        System.out.println("---------- 内存泄漏测试 ----------");
        Runtime runtime = Runtime.getRuntime();
        
        // 测试前内存状态
        runtime.gc(); // 强制垃圾回收
        long beforeMemory = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("测试前内存使用: " + (beforeMemory / 1024 / 1024) + "MB");
        
        ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hex));
        
        // 执行测试
        for (int i = 0; i < iterations; i++) {
            try {
                GBTMessage message = decoder.decode(buf.duplicate());
                if (message != null) {
                    ByteBuf encodedBuf = encoder.encode(message);
                    if (encodedBuf != null) {
                        encodedBuf.release();
                    }
                }
            } catch (Exception e) {
                // 忽略错误继续测试
            }
            
            // 每1万次检查一次内存
            if (i % 10000 == 0 && i > 0) {
                long currentMemory = runtime.totalMemory() - runtime.freeMemory();
                System.out.println("第" + i + "次 内存使用: " + (currentMemory / 1024 / 1024) + "MB");
            }
        }
        
        buf.release();
        
        // 测试后内存状态
        runtime.gc(); // 强制垃圾回收
        long afterMemory = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("测试后内存使用: " + (afterMemory / 1024 / 1024) + "MB");
        System.out.println("内存增长: " + ((afterMemory - beforeMemory) / 1024 / 1024) + "MB");
        System.out.println();
    }

    /**
     * 并发测试
     * @param hex 测试报文
     * @param threadCount 线程数量
     * @param iterationsPerThread 每线程测试次数
     */
    public static void concurrencyTest(String hex, int threadCount, int iterationsPerThread) {
        System.out.println("---------- 并发测试 ----------");
        System.out.println("线程数量: " + threadCount);
        System.out.println("每线程测试次数: " + iterationsPerThread);
        
        long startTime = System.currentTimeMillis();
        Thread[] threads = new Thread[threadCount];
        
        for (int t = 0; t < threadCount; t++) {
            final int threadId = t;
            threads[t] = new Thread(() -> {
                ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(hex));
                
                for (int i = 0; i < iterationsPerThread; i++) {
                    try {
                        GBTMessage message = decoder.decode(buf.duplicate());
                        if (message != null) {
                            message.setSerialNo((message.getSerialNo() + threadId * iterationsPerThread + i) % 65536);
                            ByteBuf encodedBuf = encoder.encode(message);
                            if (encodedBuf != null) {
                                encodedBuf.release();
                            }
                        }
                    } catch (Exception e) {
                        // 忽略错误继续测试
                    }
                }
                
                buf.release();
                System.out.println("线程 " + threadId + " 完成");
            });
        }
        
        // 启动所有线程
        for (Thread thread : threads) {
            thread.start();
        }
        
        // 等待所有线程完成
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        long totalTime = System.currentTimeMillis() - startTime;
        int totalIterations = threadCount * iterationsPerThread;
        
        System.out.println("并发测试完成!");
        System.out.println("总耗时: " + totalTime + "ms");
        System.out.println("总处理次数: " + totalIterations);
        System.out.println("处理速度: " + String.format("%.0f", (totalIterations * 1000.0 / totalTime)) + " 次/秒");
        System.out.println();
    }
}